#include "StdAfx.h"
#include "DX10ObjMesh.h"

#include "ContentManager.h"
#include "RenderContext.h"
#include "InputState.h"
#include "DX10MaterialIndexBuffer.h"
#include "Skeleton.h"
#include "GraphCamera.h"
#include "Level.h"
#include "PhysicsMesh.h"


DX10ObjMesh::DX10ObjMesh(tstring effect,tstring technique):
	m_EffectFileName(effect),
	m_pVertexBuffer(NULL),
	m_pInputLayout(NULL),
	m_pSkeleton(NULL),
	m_pDiffuseMapVariable(NULL),
	m_pEyePosVariable(NULL),
	m_pSpotLight1Variable(NULL),
	m_pSpotLight2Variable(NULL),
	m_pWorldVariable(NULL),
	m_pWorldViewProjectionVariable(NULL),
	m_pBoneMatrices(NULL),
	m_pDefaultEffect(NULL),
	m_pDefaultTechnique(NULL),
	m_SynchronizeWithPhysics(false),
	m_pActor(NULL)
{
	

	//Rotate(D3DXVECTOR3(-1.57079633f,0,0));
	Translate(D3DXVECTOR3(0,0,0));
}
DX10ObjMesh::~DX10ObjMesh(void)
{
	SAFE_RELEASE(m_pVertexBuffer);
	SAFE_RELEASE(m_pInputLayout);
	vector<DX10MaterialIndexBuffer*>::iterator it;
	for (it = m_IndexBuffers.begin(); it != m_IndexBuffers.end(); ++it )
	{
		delete *it;
	}
	SAFE_DELETE(m_pSkeleton);
}

void DX10ObjMesh::CreateEffect(ContentManager *pContentManager)
{
	m_pDefaultEffect = pContentManager->GetEffect(m_pLevel->GetDevice(), m_EffectFileName);	

	//get first technique found
	m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByIndex(0);

	GetEffectVariables(m_pDefaultEffect);

}

void DX10ObjMesh::CreateEffect(ContentManager *pContentManager, ID3D10Device* pDevice){
	m_pDefaultEffect = pContentManager->GetEffect(pDevice, m_EffectFileName);	

	//get first technique found
	m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByIndex(0);

	GetEffectVariables(m_pDefaultEffect);
}

void DX10ObjMesh::GetEffectVariables(ID3D10Effect* effect){
	m_pWorldViewProjectionVariable = effect->GetVariableByName("gWVP")->AsMatrix();
	//if(!m_pWorldViewProjectionVariable->IsValid())MessageBox(0,_T("Getting Effectvariable gWVP Failed"),_T("ERROR"),0);

	m_pWorldVariable			= effect->GetVariableByName("gWorld")->AsMatrix();
	//if(!m_pWorldVariable->IsValid())MessageBox(0,_T("Getting Effectvariable gWorld Failed"),_T("ERROR"),0);

	m_pDiffuseMapVariable = effect->GetVariableByName( "gDiffuseMap" )->AsShaderResource();
	//if(!m_pDiffuseMapVariable->IsValid())MessageBox(0,_T("Getting Effectvariable gDiffuseMap Failed"),_T("ERROR"),0);

	m_pNormalMapVariable = effect->GetVariableByName( "gNormalMap" )->AsShaderResource();
	//if(!m_pNormalMapVariable->IsValid())MessageBox(0,_T("Getting Effectvariable gNormalMap Failed"),_T("ERROR"),0);

	m_pSpotLight1Variable = effect->GetVariableByName("gLight1");
	//if(!m_pSpotLight1Variable->IsValid())MessageBox(0,_T("Getting Effectvariable gLight1 Failed"),_T("ERROR"),0);
	m_pSpotLight2Variable = effect->GetVariableByName("gLight2");
	//if(!m_pSpotLight2Variable->IsValid())MessageBox(0,_T("Getting Effectvariable gLight1 Failed"),_T("ERROR"),0);

	m_pEyePosVariable = effect->GetVariableByName("EyePos")->AsVector();
	//if(!m_pEyePosVariable->IsValid())MessageBox(0,_T("Getting Effectvariable EyePos Failed"),_T("ERROR"),0);

	if (IsAnimated())
	{
		m_pBoneMatrices = m_pDefaultEffect->GetVariableByName("gBoneMatrices");
		if(!m_pBoneMatrices->IsValid())MessageBox(0,_T("Getting Effectvariable gBoneMatrices Failed"),_T("ERROR"),0);
	}
}

void  DX10ObjMesh::UpdateEffectVariables(const RenderContext* context)const
{
	//
    // Update Shader matrix variables in effect
    //
	//create a matrix containing the multiplication of world, view and projection matrix
	//short: m_pWorldViewProjectionVariable->SetMatrix((float*)&(m_World * m_View * m_Projection));
	//bit longer:
	D3DXMATRIX wvp;
	if ( m_SynchronizeWithPhysics && m_pActor){
		NxActor* pActor = m_pActor->GetActor();
		pActor->getGlobalPose().getColumnMajor44((NxF32*)&wvp.m);
		m_pWorldVariable->SetMatrix((float*)&wvp);
	}else{
		wvp = this->GetWorldMatrix();
		m_pWorldVariable->SetMatrix((float*)&this->GetWorldMatrix());
	}
	GraphCamera* camera = context->GetCamera();
	wvp = wvp * camera->GetViewProj();
	m_pWorldViewProjectionVariable->SetMatrix((float*)&wvp);
	

	if ( IsAnimated() )
	{
		m_pBoneMatrices->SetRawValue( (void*)m_pSkeleton->GetValuePointer(),0,m_pSkeleton->GetSizeInBytes());
	}
	/*
	int spotlightsize = sizeof(SpotLight);
	if ( m_SpotLights.size()>0 )
		m_pSpotLight1Variable->SetRawValue((void*)m_SpotLights[0],0,sizeof(SpotLight));
	if ( m_SpotLights.size()>1)
		m_pSpotLight2Variable->SetRawValue((void*)m_SpotLights[1],0,sizeof(SpotLight));
	*/

	D3DXVECTOR3 pos = camera->GetPos();
	m_pEyePosVariable->SetRawValue(&pos,0,sizeof(D3DXVECTOR3));
}

void DX10ObjMesh::SetDiffuseTexture(ID3D10ShaderResourceView *texture) const{
	m_pDiffuseMapVariable->SetResource(texture);
}

void DX10ObjMesh::SetNormalMapTexture(ID3D10ShaderResourceView * texture) const{
	m_pNormalMapVariable->SetResource(texture);
}

void DX10ObjMesh::SetSkeleton(Skeleton* pSkeleton)
{
	m_pSkeleton = pSkeleton;
	
}

void DX10ObjMesh::AddAnimation(Animation * pAnimation){
	if (IsAnimated())
		m_pSkeleton->AddAnimation(pAnimation);
}

void DX10ObjMesh::AddAnimation( AnimationPtr animation){
	if( IsAnimated())
		m_pSkeleton->AddAnimation(animation);
}

void DX10ObjMesh::ActivateAnimation(tstring key,bool looping)const{
	if (IsAnimated())
		m_pSkeleton->ActivateAnimation(key,looping);
}

void DX10ObjMesh::Initialize(ContentManager* contentManager,ID3D10Device* pDevice)
{
	CreateEffect(contentManager, pDevice);
}

void DX10ObjMesh::Initialize(ContentManager* contentManager)
{
	CreateEffect( contentManager );
}

void DX10ObjMesh::Tick(const InputState& inputState)
{
	if ( IsAnimated() )
		m_pSkeleton->Animate(inputState.GetDeltaTime()*20);
}


void DX10ObjMesh::Draw(const RenderContext* renderContext) 
{
	Draw(renderContext, m_pDefaultTechnique);
}

	
void DX10ObjMesh::Draw(const RenderContext* renderContext, const ID3D10EffectTechnique* pTechnique) 
{
	ID3D10Device* pDevice = m_pLevel->GetDevice();
	
	if(!pTechnique)
	{
		MessageBox(0,_T("No Technique"),_T("ERROR"),0);
		return;
	}

	//Every object has it's own set of eg worldmatrix
	UpdateEffectVariables(renderContext);

	// Set the input layout
	pDevice->IASetInputLayout( m_pInputLayout );

	// Set primitive topology
	pDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );


	// Set vertex buffer
	UINT offset = 0;
	pDevice->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &m_VertexBufferStride, &offset );
	//
	// Renders a ShapeBase
	//
	D3D10_TECHNIQUE_DESC techDesc;
	(const_cast<ID3D10EffectTechnique*>(pTechnique))->GetDesc( &techDesc );
	for( UINT p = 0; p < techDesc.Passes; ++p )
	{
		vector<DX10MaterialIndexBuffer*>::const_iterator it;
		/*for (it=m_IndexBuffers.begin(); it != m_IndexBuffers.end(); ++it)
		{
			ID3D10EffectPass * pass = (const_cast<ID3D10EffectTechnique*>(pTechnique))->GetPassByIndex( p );
			(*it)->Draw(pDevice,this,pass);
		}*/
		it = m_IndexBuffers.begin();
		ID3D10EffectPass * pass = (const_cast<ID3D10EffectTechnique*>(pTechnique))->GetPassByIndex( p );
		(*it)->Draw(pDevice,this,pass);
	}
}

void DX10ObjMesh::OnResize()
{
}